﻿using System;
using System.Collections.Generic;
using System.Reflection;
using Development.Network.Msg;
using Development.Tools;

namespace Development.Network.Rpc
{
    /*rpc 调用*/

    //rpc 协议 调用协议
    public class RpcRequst : JsonMsg
    {
        public string RpcUID;
        /// <summary>
        /// 函数名
        /// </summary>
        public string MethodName = "";
        /// <summary>
        /// 参数
        /// </summary>
        public string[] Args;

        protected override void WriteMsgId()
        {
            _MsgId = 20;
        }
    }

    /// <summary>
    /// 返回值
    /// </summary>
    public class RpcReturnVal : JsonMsg
    {
        public string RpcUID;
        public string ReturnVal;
        protected override void WriteMsgId()
        {
            _MsgId = 21;
        }
        public T ToObject<T>()
        {
            return fastJSON.JSON.ToObject<T>(ReturnVal.ToString());
        }

    }

    /// <summary>
    /// rpc 标记
    /// </summary>
    public class RpcAttribute : Attribute
    {

    }

    /// <summary>
    /// rpc调用
    /// </summary>
    public class Rpc
    {
        private readonly object _flagLock = new object();
        protected Dictionary<string, MethodInfo> _rpcMethodCache = new Dictionary<string, MethodInfo>();
        protected Dictionary<string, Action<RpcReturnVal>> _returnVals = new Dictionary<string, Action<RpcReturnVal>>();
        /// <summary>
        /// 获取调用id
        /// </summary>
        public Rpc()
        {
            var methods = this.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
            foreach (var m in methods)
            {
                var rpcAttr = Attribute.GetCustomAttribute(m, typeof(RpcAttribute));
                if (rpcAttr != null)
                {
                    _rpcMethodCache.Add(m.Name, m);
                }
            }
            _returnVals.Clear();
        }
        /// <summary>
        /// rpc 调用
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="callback"></param>
        /// <param name="args"></param>
        public void RpcCall(ISender sender, string methodName, params object[] args)
        {
            var send = new RpcRequst() { MethodName = methodName, Args = GetJsonParams(args) };
            RpcSend(sender, send);
        }

        private string [] GetJsonParams(object [] args)
        {
            var jsonParams = new string[args.Length];
            for (int i = 0; i < args.Length; ++i)
            {
                jsonParams[i] = fastJSON.JSON.ToJSON(args[i]);
            }
            return jsonParams;
        }

        /// <summary>
        /// 有返回值 服务器使用
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="methodName"></param>
        /// <param name="returnVal"></param>
        /// <param name="args"></param>
        public void RpcCall(ISender sender, string methodName, Action<RpcReturnVal> returnVal, params object[] args)
        {
            var send = new RpcRequst() { MethodName = methodName, Args = GetJsonParams(args) };
            if (returnVal != null)
            {
                send.RpcUID = Guid.NewGuid().ToString();
                lock (_flagLock)
                {
                    _returnVals.Add(send.RpcUID, returnVal);
                }
            }
            RpcSend(sender, send);
        }
        /// <summary>
        /// rpc 调用 客户端使用
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="args"></param>
        public void RpcCall(string methodName, params object[] args)
        {
            var send = new RpcRequst() { MethodName = methodName, Args = GetJsonParams(args) };
            RpcSend(null, send);
        }

        /// <summary>
        /// 用于rpc 客户端 有返回值
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="returnVal"></param>
        /// <param name="args"></param>
        public void RpcCall(string methodName, Action<RpcReturnVal> returnVal, params object[] args)
        {
            var send = new RpcRequst() { MethodName = methodName, Args = GetJsonParams(args) };
            if (returnVal != null)
            {
                send.RpcUID = Guid.NewGuid().ToString();
                lock (_flagLock)
                {
                    _returnVals.Add(send.RpcUID, returnVal);
                }
            }
            RpcSend(null, send);
        }


        protected virtual void RpcSend(ISender sender, RpcRequst requst)
        {

        }


        protected void RpcRecv(MsgPacket packet)
        {
            DateTime startTime = DateTime.Now;

            ISender sender = packet.UserToken as ISender;
            if (sender == null)
            {
                return;
            }
            if (packet.MsgId == 20)
            {
                var rpcMsg = MsgPacket.PacketToObj<RpcRequst>(packet);
                if (rpcMsg != null)
                {
                    MethodInfo method = null;
                    if (_rpcMethodCache.TryGetValue(rpcMsg.MethodName, out method))
                    {
                        List<object> parametes = new List<object>();
                        parametes.Add(sender);
                        parametes.AddRange(rpcMsg.Args);
                        var methodParametes = method.GetParameters();
                        if(parametes.Count != methodParametes.Length)
                        {
                            Log.WriteLog(ELogLevel.LOG_ERROR, "paramtes count not same, methodName = " + method.Name);
                            return;
                        }

                        List<object> modifyParames = new List<object>();
                        for(int i = 0; i < methodParametes.Length;++i)
                        {
                            var paramInfo = methodParametes[i];
                            if(i != 0)
                            {
                                modifyParames.Add(fastJSON.JSON.ToObject(parametes[i].ToString(),paramInfo.ParameterType));
                            }
                            else
                            {
                                modifyParames.Add(parametes[i]);
                            }
                        }
                        object returnVal = method.Invoke(this, modifyParames.ToArray());
                        if (returnVal != null && !string.IsNullOrEmpty(rpcMsg.RpcUID))
                        {
                            var returnMsg = new RpcReturnVal() { RpcUID = rpcMsg.RpcUID, ReturnVal = fastJSON.JSON.ToJSON(returnVal) };
                            sender.Send(returnMsg.Pack());
                        }
                    }
                }

            }
            else if (packet.MsgId == 21)
            {
                RpcReturnVal returnVal = MsgPacket.PacketToObj<RpcReturnVal>(packet);
                if (returnVal == null)
                {
                    return;
                }
                Action<RpcReturnVal> action = null;
                lock (_flagLock)
                {
                    if (_returnVals.TryGetValue(returnVal.RpcUID, out action))
                    {
                        if (action != null)
                        {
                            action(returnVal);
                        }
                        _returnVals.Remove(returnVal.RpcUID);
                    }
                }
            }
            else
            {
                Log.WriteLog(ELogLevel.LOG_ERROR, "未知 msgId：" + packet.MsgId);
            }
            Console.WriteLine("take :" + (DateTime.Now - startTime).TotalMilliseconds);
        }
    }
}
